const getEdge = (total_index, index, type) => {
    if (type === 'max') {
        for (; index < total_index.length; index++) {
            const item = total_index[index];
            if (Number(item) === Number(item)) { return item; }
        }
        return total_index.length;
    }

    for (; index >= 0 && index < total_index.length; index--) {
        const item = total_index[index];
        if (Number(item) === Number(item)) { return item; }
    }

    return 0;
}

const getComapreRowIndex = (compare_total_list = [], compare_bbox_list = [], total_index = [], index, type) => {
    let key = null;
    if (Array.isArray(index)) {
        key = Math.max(getEdge(total_index, index[0], 'min'), getEdge(total_index, index[index.length - 1], 'max'));
    } else {
        key = Math.max(getEdge(total_index, index, 'min'), getEdge(total_index, index, 'max'));
    }

    const itemIndex = compare_total_list.findIndex((data) => data === key);

    return `${compare_bbox_list[itemIndex]}_${type}`
}

const mergeGroup = (list = [], total_index_list = [], compare_total_list = [], compare_bbox_list = []) => {
    let type = '';
    let content = '';
    const bbox_indexs = [];
    const indexs = [];
    const { bbox_index } = list[list.length - 1];

    list.forEach((item) => {
        if (type !== item.type) { type = item.type; }
        content += item.content;
        bbox_indexs.push(item.bbox_index);
        indexs.push(item.index);
    });

    return { 
        type, 
        content, 
        bbox_indexs, 
        bbox_index, 
        indexs, 
        id: `${getEdge(total_index_list, indexs[0], 'min')}_${getEdge(total_index_list, indexs[indexs.length - 1] + 1, 'max')}_${type}`,
        compare_row: getComapreRowIndex(compare_total_list, compare_bbox_list, total_index_list, indexs, type),
     };
};

function getTextLen(val = '') {
    if (val === null) return 0;

    if (typeof val !== 'string') { val += ''; }

    return val.replace(/[^\x00-\xff]/g, '01').length;
}

const getInfo = (text, total_index_list, bbox_index_list, compare_total_list, compare_bbox_list) => {
    const list = [];
    let group = [];

    total_index_list.forEach((type, index) => {
        if (isNaN(type)) {
            const content = text[index];
            const bbox_index = bbox_index_list[index];

            const nextItem = total_index_list[index + 1];
            if (nextItem && String(nextItem).replace('o', '') === type.replace('o', '')) {
                group.push({ type, content, bbox_index, index });
            } else {
                if (group.length > 0) {
                    group.push({ type, content, bbox_index, index });
                    list.push(mergeGroup(group, total_index_list, compare_total_list, compare_bbox_list));
                    group = [];
                } else {
                    list.push({ 
                        type, 
                        content, 
                        bbox_index, 
                        indexs: [index], 
                        id: `${getEdge(total_index_list, index, 'min')}_${getEdge(total_index_list, index, 'max')}_${type}`,
                        compare_row: getComapreRowIndex(compare_total_list, compare_bbox_list, total_index_list, index, type),
                    });
                }
            }
        }
    });

    return list;
}

const getWH = (img_size = []) => {
    const [w, h] = img_size;
    return { w, h }
};

// 坐标计算
const getBoxInfo = (
    { items: bboxes = [], txtItems = [] }, 
    bbox_indexs = [], 
    content = '',
) => {
    const list = [];

    bbox_indexs.forEach((bbox_index, index) => {
        const [, box_number, text_number] = bbox_index.split('.');
        const [box1, box2, box3] = bboxes[box_number];

        let txtLen = 0;
        const con = txtItems[box_number];
        con.split('').forEach((item) => {
            txtLen += getTextLen(item);
        });

        let txtSubLen = 0;
        const subCon = con.substr(0, parseInt(text_number, 10) + 1);
        subCon.split('').forEach((item) => {
            txtSubLen += getTextLen(item);
        });

        const h = Math.abs(box3[1] - box2[1]);
        const [x, y] = box1;
        const unitWidth = Math.abs(box2[0] - box1[0]) / txtLen;
        let w = 0;

        const txt = content.charAt(index);
        const codeType = getTextLen(txt);

        if (codeType === 2) { 
            w += unitWidth * 2;
        } else { 
            w += unitWidth; 
        }

        const rotate = Math.atan2((box2[1] - box1[1]), (box2[0] - box1[0])) * 180 / (Math.PI);

        list.push({ w, h, x: x + (txtSubLen - codeType) * unitWidth, y, txt, rotate });
    });

    return list;
};

const getMasks = (
    pageId, 
    bboxes_info,
    info_list = [], 
) => {
    const page_number = parseInt(pageId.split('.')[0], 10);
    const masks = [];

    // 找到当前页的所有点
    info_list.forEach((item) => {
        const { bbox_index, bbox_indexs, content } = item;
        // 第⼀位数字0代表是第⼀张图⽚，第⼆位数字12代表是该图⽚中的第12个⽂本框，第三位数字4代表是该⽂本框中的第4个⽂字
        const [img_number] = bbox_index.split('.');
        const bbox_index_list = (bbox_indexs && bbox_indexs.length > 0) ? bbox_indexs : [bbox_index];

        if (parseInt(img_number, 10) === page_number) {
            masks.push({ ...item, bboxes: getBoxInfo(bboxes_info, bbox_index_list, content) });
        }
    });

    return masks;
};

const getDebugDotWHXY = (bboxes = []) => {
    const [x1, y1] = bboxes[0];
    const [x2, y2] = bboxes[1];
    const rotate = Math.atan2((y2 - y1), (x2 - x1)) * 180 / (Math.PI);

    return bboxes.map((item) => ({
        w: 50,
        h: 50,
        x: item[0],
        y: item[1],
        rotate,
    }));
};

// 绘制原始数据的点
const getDebugDots = (bboxes = []) => {
    const rows = [];

    bboxes.forEach((item) => {
        rows.push(...getDebugDotWHXY(item));
    });

    return rows;
};

const getDebugRowWHXY = (bboxes = []) => {
    const [box1, box2, box3] = bboxes;
    const w = Math.abs(box2[0] - box1[0]);
    const h = Math.abs(box3[1] - box2[1]);
    const [x, y] = box1;
    const rotate = Math.atan2((box2[1] - box1[1]), (box2[0] - box1[0])) * 180 / (Math.PI);

    return { w, h, x, y, rotate };
};

// 绘制原始数据的行
const getDebugRows = (bboxes = []) => {
    const rows = [];

    bboxes.forEach((item) => {
        rows.push({ ...getDebugRowWHXY(item) });
    });

    return rows;
};

const getRowWHXY = (bboxes = []) => {
    const [box1] = bboxes;
    const [x, y] = box1;

    return { w: 1, h: 1, x, y };
};

const getRows = (pageId, bboxes = []) => {
    const page_number = parseInt(pageId.split('.')[0], 10);
    const rows = [];

    bboxes.forEach((item, index) => {
        rows.push({ ...getRowWHXY(item), id: `${page_number}.${index}` });
    });

    return rows;
};

// 修正数据不规范
const getBboxsInfo = ({ bboxes = [], texts = [] }) => {
    const items = [];
    const txtItems = [];

    bboxes.forEach((item, index) => {
        if (item.length === 4) {
            items.push(item);
            txtItems.push(texts[index]);
        } else {
            item.forEach((data, index2) => {
                if (data.length === 4) {
                    items.push(data);
                }
                txtItems.push(texts[index][index2]);
            });
        }
    });

    return { items, txtItems };
};

// 获取每页的坐标和图片
const getOcrInfo = (ocr, docType, infoList, debug) => {
    const result = [];

    Object.keys(ocr).forEach((key) => {
        const item = ocr[key].text_info.general_ocr_res;
        item.bboxes_info = getBboxsInfo(item);

        result.push({
            pageId: parseInt(key, 10),
            img_url: `http://localhost:3000/${docType}/${key}`,
            img_size: getWH(item.image_size),
            masks: getMasks(key, item.bboxes_info, infoList),
            rows: getRows(key, item.bboxes_info.items),
            ...(debug === 'row' ? {
                debug_rows: getDebugRows(item.bboxes_info.items),
            } : {}),
            ...(debug === 'dot' ? {
                debug_dots: getDebugDots(item.bboxes_info.items),
            } : {}),
        })
    });

    return result;
};

module.exports = (data = {}, debug = 0) => {
    const {
        origin: {
            index: {
                content: origin_content = '',
                total_index: origin_total_index = [],
                bbox_index: origin_bbox_index = [],
            },
            ocr: origin_ocr = [],
        } = {},
        modified: {
            index: {
                content: modified_content = '',
                total_index: modified_total_index = [],
                bbox_index: modified_bbox_index = [],
            },
            ocr: modified_ocr = [],
        } = {},
    } = data;

    // 解析所以差异点
    const origin_info_list = getInfo(origin_content, origin_total_index, origin_bbox_index, modified_total_index, modified_bbox_index);
    const modified_info_list = getInfo(modified_content, modified_total_index, modified_bbox_index, origin_total_index, origin_bbox_index);

    const result = [];

    // 把所有差异点按照页进行拆分
    const originItems = getOcrInfo(origin_ocr, 'origin', origin_info_list, debug);
    const modifiedItems = getOcrInfo(modified_ocr, 'modified', modified_info_list, debug);
    const len = Math.max(originItems.length, modifiedItems.length);
    for (let i = 0; i < len; i += 1) {
        const pageInfo = { pageId: i };
        const origin = originItems.find(({ pageId }) => (pageId === i)) || pageInfo;
        const modified = modifiedItems.find(({ pageId }) => (pageId === i)) || pageInfo;
  
        result.push({ origin, modified });
    }

    return result;
};
